package com.nd.fastdp.workflow.service;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.nd.fastdp.framework.pojo.dto.DelParam;
import com.nd.fastdp.workflow.constant.NodeTypes;
import com.nd.fastdp.workflow.constant.ProcinstFinishedFlagEnum;
import com.nd.fastdp.workflow.constant.ProcinstStateType;
import com.nd.fastdp.workflow.constant.TaskFinishedFlagEnum;
import com.nd.fastdp.workflow.convert.ProcinstConvert;
import com.nd.fastdp.workflow.dao.ProcinstMapper;
import com.nd.fastdp.workflow.model.bo.procdef.ProcdefBO;
import com.nd.fastdp.workflow.model.bo.procinst.ProcinstBO;
import com.nd.fastdp.workflow.model.bo.task.TaskBO;
import com.nd.fastdp.workflow.model.dto.procinst.ProcinstModifyParam;
import com.nd.fastdp.workflow.model.dto.procinst.ProcinstQueryParam;
import com.nd.fastdp.workflow.model.dto.procinst.ProcinstStartParam;
import com.nd.fastdp.workflow.model.dto.procinst.ProcinstStatisticsParam;
import com.nd.fastdp.workflow.model.dto.task.TaskAddParam;
import com.nd.fastdp.workflow.model.entity.Procinst;
import com.nd.fastdp.workflow.model.pojo.Node;
import com.nd.fastdp.workflow.serivce.ProcdefService;
import com.nd.fastdp.workflow.serivce.ProcinstService;
import com.nd.fastdp.workflow.serivce.TaskService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Map;

@Service
public class ProcinstServiceImpl implements ProcinstService {

    @Autowired
    private ProcinstMapper procinstMapper;

    @Autowired
    private ProcdefService procdefService;

    @Autowired
    private TaskService taskService;

    @Autowired
    private Map<String, WorkFlowListener> workFlowListenerMap;

    @Override
    @Transactional
    public ProcinstBO start(ProcinstStartParam param) {

        Procinst procinst = ProcinstConvert.INSTANCE.from(param);

        //获取流程定义
        ProcdefBO procdef = procdefService.get(param.getProcdefId());

        //创建流程实例
        procinst.setGroupId(procdef.getGroupId());
        procinst.setProcdefName(procdef.getName());
        procinst.setProcdefConfig(procdef.getConfig());
        procinst.setFlowVal(param.getFlowVal());
        procinst.setState(ProcinstStateType.IN_APPROVAL.getValue());

        if(StringUtils.isEmpty(procinst.getTitle())){
            procinst.setTitle(procinst.getCreateUserName() + "提交的" + procinst.getProcdefName());
        }

        procinst.setStartTime(System.currentTimeMillis());
        procinst.setFinished(ProcinstFinishedFlagEnum.IN_APPROVAL.getValue());

        procinst.setStep(-1);//启动后直接执行到第一个审批节点

        //保存流程实例
        procinstMapper.insert(procinst);

        Boolean hasNext = false;
        List<Node> nodeList = Node.parseList(procinst.getNodeList());
        for (int i = 0; i < nodeList.size(); i++){

            addStep(procinst.getId());

            if(nodeList.get(i).getProperties().getMenbers() == null && nodeList.get(i).getProperties().getMenbers().size() <= 0){

                continue;
            }

            //添加任务
            TaskAddParam taskAddParam = new TaskAddParam();
            taskAddParam.setProcinstId(procinst.getId());
            taskAddParam.setNode(nodeList.get(i));

            TaskBO taskBO = taskService.add(taskAddParam);

            if(NodeTypes.APPROVER.getValue().equals(nodeList.get(i).getType())){//抄送任务自动结束直接转发到第一个审批节点中

                hasNext = true;

                break;
            }


        }

        //只有抄送没有审批
        if(!hasNext){
            finished(procinst.getId(), ProcinstStateType.PASS.getValue());
        }

        return get(procinst.getId());
    }

    @Override
    public void addStep(String id){

        Procinst target = procinstMapper.selectById(id);

        Procinst procinst = new Procinst();
        procinst.setId(id);
        procinst.setStep(target.getStep() + 1);

        procinstMapper.updateById(procinst);
    }

    @Override
    public void recall(String id) {

        Procinst target = procinstMapper.selectById(id);

        taskService.finished(target.getTaskId(), TaskFinishedFlagEnum.END.getValue());

        finished(target.getId(), ProcinstStateType.RECALL.getValue());
    }

    @Override
    public ProcinstBO modify(ProcinstModifyParam param) {

        Procinst procinst = ProcinstConvert.INSTANCE.from(param);
        procinstMapper.updateById(procinst);

        return get(procinst.getId());
    }

    @Override
    public void modify(String id, String flowVal) {

        Procinst procinst = new Procinst();
        procinst.setId(id);
        procinst.setFlowVal(flowVal);

        procinstMapper.updateById(procinst);
    }

    @Override
    public void del(DelParam param) {
        procinstMapper.del(param);
    }

    @Override
    public ProcinstBO get(String id) {
        return ProcinstConvert.INSTANCE.to(procinstMapper.selectById(id));
    }

    @Override
    @Transactional
    public ProcinstBO finished(String id, Integer state) {

        Procinst procinst = procinstMapper.selectById(id);

        procinst.setEndTime(System.currentTimeMillis());
        procinst.setDuration(procinst.getEndTime() - procinst.getStartTime());
        procinst.setFinished(ProcinstFinishedFlagEnum.END.getValue());
        procinst.setState(state);
        procinst.setTaskId("");
        procinst.setNodeId("");
        procinst.setNodeName("结束");

        procinstMapper.updateById(procinst);

        ProcdefBO procdefBO = procdefService.get(procinst.getProcdefId());
        WorkFlowListener workFlowListener = workFlowListenerMap.get("workFlowListener_" + procdefBO.getCode());
        if(workFlowListener == null){
            workFlowListener = workFlowListenerMap.get("defaultWorkFlowListener");
        }

        if(ProcinstStateType.PASS.getValue() == state){
            workFlowListener.pass(get(id));
        }else if(ProcinstStateType.REJECT.getValue() == state){//在待办处回调

        }else if(ProcinstStateType.RECALL.getValue() == state){
            workFlowListener.recall(get(id));
        }

        return ProcinstConvert.INSTANCE.to(procinstMapper.selectById(id));
    }

    @Override
    public ProcinstBO updateTask(String id, String taskId) {

        Procinst procinst = procinstMapper.selectById(id);
        TaskBO taskBO = taskService.get(taskId);

        Node node = Node.get(procinst.getNodeList(), procinst.getStep());

        procinst.setTaskId(taskId);
        procinst.setNodeId(taskBO.getNodeId());
        procinst.setNodeName(node.getProperties().getTitle());

        procinstMapper.updateById(procinst);

        return ProcinstConvert.INSTANCE.to(procinstMapper.selectById(id));
    }

    //所有查询
    @Override
    public Page<ProcinstBO> page(ProcinstQueryParam param) {

        IPage<Procinst> page = procinstMapper.page(param.getPage(), param);

        return ProcinstConvert.INSTANCE.to(page);
    }

    //我发起的
    @Override
    public Page<ProcinstBO> mySendPage(ProcinstQueryParam param) {

        IPage<Procinst> page = procinstMapper.mySendPage(param.getPage(), param);

        return ProcinstConvert.INSTANCE.to(page);
    }

    //待处理
    @Override
    public Page<ProcinstBO> waitApprovePage(ProcinstQueryParam param) {

        IPage<Procinst> page = procinstMapper.waitApprovePage(param.getPage(), param);

        return ProcinstConvert.INSTANCE.to(page);
    }

    //已处理
    @Override
    public Page<ProcinstBO> alreadyApprovePage(ProcinstQueryParam param) {

        IPage<Procinst> page = procinstMapper.alreadyApprovePage(param.getPage(), param);

        return ProcinstConvert.INSTANCE.to(page);
    }

    @Override
    public Integer statistics(ProcinstStatisticsParam param) {
        return procinstMapper.statistics(param);
    }

}
